package com.itheima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.hmall.common.dto.Item;
import com.hmall.common.dto.PageDTO;

import com.hmall.feign.ItemFeign;
import com.itheima.search.domain.ItemDoc;
import com.itheima.search.domain.RequestParams;
import com.itheima.search.service.SearchService;


import org.elasticsearch.action.bulk.BulkRequest;

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;

import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;

import org.springframework.util.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    RestHighLevelClient client;

    @Autowired
    private ItemFeign itemFeign;

    /**
     * 批量导入es
     */
    @Override
    public void importes() {
        PageDTO<Item> pageDTO = itemFeign.list(1, 1);
        Long total = pageDTO.getTotal();
        Long totalPage=total/1000;
        for(int i=1;i<=totalPage+1;i++){
            PageDTO<Item> list = itemFeign.list(i, 1000);
            List<Item> items = list.getList();
            BulkRequest bulkRequest=new BulkRequest();
            for (Item item : items) {
                IndexRequest indexRequest=new IndexRequest("item");
                indexRequest.id(item.getId().toString());
                indexRequest.source(JSON.toJSONString(item), XContentType.JSON);
                bulkRequest.add(indexRequest);
            }
            try {
                client.bulk(bulkRequest,RequestOptions.DEFAULT);
                System.out.println("第"+i+"页导入完成");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//    @Override
//    public Map<String,List<String>> filters(RequestParams params) {
//        Map<String,List<String>> maps=new HashMap<>();
//        SearchRequest request=new SearchRequest("item");
//        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
//        QueryBuilder queryBuilder = getQueryBuilder(params, searchSourceBuilder);
//        searchSourceBuilder.query(queryBuilder);
//        searchSourceBuilder.size(0);
//        AggregationBuilder brandAgg= AggregationBuilders.terms("brandAgg");
//        ((TermsAggregationBuilder) brandAgg).field("brand");
//        searchSourceBuilder.aggregation(brandAgg);
//        AggregationBuilder categoryAgg= AggregationBuilders.terms("categoryAgg");
//        ((TermsAggregationBuilder) brandAgg).field("category");
//        searchSourceBuilder.aggregation(categoryAgg);
//        request.source(searchSourceBuilder);
//        try {
//            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//            Aggregations aggregations = response.getAggregations();
//            Terms agg = aggregations.get("brandAgg");
//            List<? extends Terms.Bucket> buckets = agg.getBuckets();
//            List<String> brands=new ArrayList<>();
//            for (Terms.Bucket bucket : buckets) {
//                String keyAsString = bucket.getKeyAsString();
//                brands.add(keyAsString);
//            }
//            maps.put("brand",brands);
//
//
//            Terms agg1 = aggregations.get("categoryAgg");
//            List<? extends Terms.Bucket> buckets1 = agg1.getBuckets();
//            List<String> categorys=new ArrayList<>();
//            for (Terms.Bucket bucket : buckets1) {
//                String keyAsString = bucket.getKeyAsString();
//                categorys.add(keyAsString);
//            }
//            maps.put("category",categorys);
//              return  maps;
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return  null;
//    }


    @Override
    public Map<String, List<String>> filters(RequestParams params)  {
        Map<String,List<String>> map=new HashMap<>();
        SearchRequest request=new SearchRequest("item");
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        QueryBuilder queryBuilder = getQueryBuilder(params, sourceBuilder);
        sourceBuilder.query(queryBuilder);
        AggregationBuilder categoryAgg= AggregationBuilders.terms("categoryAgg");
        ((TermsAggregationBuilder) categoryAgg).field("category");
        sourceBuilder.aggregation(categoryAgg);
        AggregationBuilder brandAgg= AggregationBuilders.terms("brandAgg");
        ((TermsAggregationBuilder) brandAgg).field("brand");
        ((TermsAggregationBuilder) brandAgg).size(100);
        sourceBuilder.aggregation(brandAgg);
        request.source(sourceBuilder);
        sourceBuilder.size(0);
        SearchResponse response = null;
        try {
            response = client.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Aggregations aggregations = response.getAggregations();
        Terms aggBrand = aggregations.get("brandAgg");
        List<? extends Terms.Bucket> buckets = aggBrand.getBuckets();
        List<String> brands=new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            String keyAsString = bucket.getKeyAsString();
            brands.add(keyAsString);
        }
        map.put("brand",brands);

        Terms aggCategory = aggregations.get("categoryAgg");
        List<? extends Terms.Bucket> buckets1 = aggCategory.getBuckets();
        List<String> categorys=new ArrayList<>();
        for (Terms.Bucket bucket : buckets1) {
            String keyAsString = bucket.getKeyAsString();
            categorys.add(keyAsString);
        }
        map.put("category",categorys);

        System.out.println(map.size());
        return map;
    }

    @Override
    public PageDTO search(RequestParams requestParams) {

        SearchRequest request=new SearchRequest("item");
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();


        QueryBuilder queryBuilder=getQueryBuilder(requestParams,searchSourceBuilder);
        FunctionScoreQueryBuilder functionScoreQuery= QueryBuilders.functionScoreQuery(
                queryBuilder,new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD",true),
                                ScoreFunctionBuilders.weightFactorFunction(10)
                        )
                }
        );

        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<em>");
        highlightBuilder.postTags("</em>");
        highlightBuilder.requireFieldMatch(false);
        searchSourceBuilder.highlighter(highlightBuilder);
        searchSourceBuilder.query(functionScoreQuery);
        searchSourceBuilder.from((requestParams.getPage()-1)*requestParams.getSize());
        searchSourceBuilder.size(requestParams.getSize());
        if(requestParams.getSortBy().equals("default")){
            searchSourceBuilder.sort("_score", SortOrder.DESC);
        }else if(requestParams.getSortBy().equals("sold")){
            searchSourceBuilder.sort(requestParams.getSortBy(),SortOrder.DESC);
        }else{
            searchSourceBuilder.sort(requestParams.getSortBy(),SortOrder.ASC);
        }
        request.source(searchSourceBuilder);
        SearchResponse response=null;
        try {
             response = client.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHits searchHits = response.getHits();
        SearchHit[] hits = searchHits.getHits();

        PageDTO pageDTO=new PageDTO();
        pageDTO.setTotal(searchHits.getTotalHits().value);
        List<ItemDoc> itemDtos=new ArrayList<>();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            ItemDoc ItemDoc = JSON.parseObject(source, ItemDoc.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField nameField = highlightFields.get("name");
            if(nameField !=null){
                String name = nameField.getFragments()[0].string();
                ItemDoc.setName(name);
            }
            itemDtos.add(ItemDoc);
        }
        pageDTO.setList(itemDtos);
        return pageDTO;
    }



    private QueryBuilder getQueryBuilder(RequestParams params, SearchSourceBuilder searchSourceBuilder) {
        QueryBuilder queryBuilder=QueryBuilders.boolQuery();
        if(StringUtils.isEmpty(params.getKey())){
            ((BoolQueryBuilder) queryBuilder).must(QueryBuilders.matchAllQuery());
        }else{
            ((BoolQueryBuilder) queryBuilder).must(QueryBuilders.matchQuery("all",params.getKey()));
        }
        if(!StringUtils.isEmpty(params.getCategory())){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.termQuery("category",params.getCategory()));
        }

        if(!StringUtils.isEmpty(params.getBrand())){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.termQuery("brand",params.getBrand()));
        }
        if(!StringUtils.isEmpty(params.getMaxPrice())){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.rangeQuery("price").lte(params.getMaxPrice()));
        }
        if(!StringUtils.isEmpty(params.getMinPrice())){
            ((BoolQueryBuilder) queryBuilder).filter(QueryBuilders.rangeQuery("price").gt(params.getMinPrice()));
        }
    return queryBuilder;
    }
}
